package com.netstar.jsonparser;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Iterator;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import android.util.Log;

import com.netstar.property.AbstractProperty;
import com.netstar.property.ArrayProperty;
import com.netstar.property.NestedProperty;
import com.netstar.property.PrimitiveProperty;
import com.netstar.property.Property;
import com.netstar.property.PropertyClass;

public abstract class AbstractParser {

	protected static final String RESULT = "result";

	protected String dataSource;

	public AbstractParser(String data) {
		this.dataSource = data;
	}

	protected abstract String getClassName();

	protected AbstractProperty getProperty(String properName, PropertyClass klass) {
		return klass.properties.get(properName);
	}

	public abstract Object parse() throws IOException, JSONException;

	protected ArrayList<Property> parseArray(String className, JSONArray array) throws JSONException, IOException {
		if (null == array) {
			return null;
		}
		int len = array.length();
		ArrayList<Property> resources = new ArrayList<Property>(len);
		for (int i = 0; i < len; i++) {
			JSONObject temp = array.getJSONObject(i);
			Property prop = parseObject(className, temp);
			resources.add(prop);
		}
		return resources;
	}

	protected final Property parseObject(JSONObject obj) throws IOException, JSONException {
		String className = getClassName();
		PropertyClass klass = Property.getKlass(className);
		if (null == klass) {
			throw new JSONException("unknown class '" + className + "'");
		}
		return parseJsonObjec(klass, obj);
	}

	private Property parseObject(String className, JSONObject obj) throws IOException, JSONException {
		PropertyClass klass = Property.getKlass(className);
		if (klass == null) {
			throw new JSONException("unknown class '" + className + "'");
		}
		return parseJsonObjec(klass, obj);
	}

	private Property parseJsonObjec(PropertyClass klass, JSONObject obj) throws JSONException, IOException {
		if (klass == null) {
			throw new JSONException("klass is 'null' !");
		}

		Property property = klass.factory();
		String key = null;
		Object value = null;
		@SuppressWarnings("unchecked")
		Iterator<String> it = obj.keys();
		while (it.hasNext()) {
			key = it.next();
			value = obj.get(key);
			if (value == JSONObject.NULL) {
				value = null;
			}
			// AbstractProperty prop = klass.mProperties.get(key);
			AbstractProperty prop = getProperty(key, klass);
			if (prop == null) {
				// Unknown property
			} else if (prop instanceof PrimitiveProperty) {
				PrimitiveProperty pprop = (PrimitiveProperty) prop;
				pprop.parse(property, value);
			} else if (prop instanceof NestedProperty) {
				NestedProperty nprop = (NestedProperty) prop;
				nprop.set(property, parseJsonObjec(Property.getKlass(nprop.getType()), (JSONObject) value));
			} else if (prop instanceof ArrayProperty) {
				ArrayProperty aprop = (ArrayProperty) prop;
				aprop.set(property, parseArray(getClassName(), (JSONArray) value));
			} else {
				Log.e("Parser", "unknown property!");
			}
		}
		return property;
	}
}
